// compile: g++ -o new new.cc -std=c++17
// run: ./new
#include <iostream>
#include <string>
#include <string_view>
using namespace std;
class XXX {
 public:
  XXX() { cout << "XXX()" << endl; }
  XXX(int data) : data_(data) { cout << "XXX(int)" << endl; }
  ~XXX() { cout << "~XXX()" << endl; }
  // operator new实现
  void* operator new(size_t size) {
    cout << "XXX new : allocating " << size << " bytes!" << endl;
    return malloc(size);
  }
  // operator new[]实现
  void* operator new[](size_t size) {
    cout << "XXX new[] : allocating " << size << " bytes!" << endl;
    return malloc(size);
  }
  // operator delete实现
  void operator delete(void* p) {
    cout << "XXX delete" << endl;
    free(p);
  }
  // operator delete[]实现
  void operator delete[](void* p) {
    cout << "XXX delete[]" << endl;
    free(p);
  }
  // placement new实现
  void* operator new(size_t size, void* start) {
    cout << "XXX placement new" << endl;
    return start;
  }
  void Show() { cout << data_ << endl; }

 private:
  int data_;
};
// 当类型为 int, float 等内置类型时，new、delete、new[]、delete[]不需要配对使用;
// 当是自定义类型时，new、delete 和 new[]、delete[]才需要配对使用。
void Test1() {
  XXX* ptr1 = new XXX;
  delete ptr1;
  // 使用new[],头部多申请 4 个字节，用于存储数组长度
  XXX* ptr2 = new XXX[3];
  // delete ptr2; 运行出错，只调用了一次析构函数
  // delete[]时候会向 前找 4 个字节获取长度
  delete[] ptr2;
}

void* operator new(size_t size) {
  cout << "global new : allocating " << size << " bytes!" << endl;
  return malloc(size);
}
void* operator new[](size_t size) {
  cout << "global new[] : allocating " << size << " bytes!" << endl;
  return malloc(size);
}
void operator delete(void* p) {
  cout << "global delete" << endl;
  free(p);
}
void operator delete[](void* p) {
  cout << "global delete[]" << endl;
  free(p);
}
void* operator new(size_t size, void* start, char extra) {
  cout << "global placement new" << endl;
  return start;
}
// placement使用场景: 避免空间的重复分配与释放
// char *buf  = new char[sizeof(string)]; // pre-allocated buffer
// string *p = new (buf) string("hi");    // placement new
// string *q = new string("hi");          // ordinary heap allocation
void Test2() {
  // new[]
  int* ptr1 = new int[5];
  delete[] ptr1;
  // new
  char* ptr2 = new char('c');
  delete ptr2;
  // placement new
  char* ptr3 = new char('c');
  char* ptr4 = new (ptr3, '0') char('b');
  cout << *ptr4 << endl;
  delete ptr3;
}
// new[] 分配的空间的前面是什么？
void Test3() {
  XXX* ptr1 = new XXX;
  ptr1->Show();
  delete ptr1;
  cout << "--------------" << endl;
  XXX* ptr2 = new XXX(1);
  ptr2->Show();
  cout << "--------------" << endl;
  XXX* ptr3 = new (ptr2) XXX(2);
  ptr2->Show();
  ptr3->Show();
  cout << "--------------" << endl;
  delete ptr2;  // ptr2 == ptr3
  XXX* ptr4 = new XXX[2];
  // 在2020macbook m1air,clang 12.0.5上，
  // 使用了16个字节来记录数组的长度以及内存对齐，
  // 这一部分只有当类有自定义析构函数时，才会生成
  // 否则，不需要执行析构函数，直接释放内存即可；
  delete[] ptr4;
  cout << "--------------" << endl;
}

// malloc使用
// void* malloc( std::size_t size );
// size	- number of bytes to allocate
void Test4() {
  int* p = (int*)malloc(sizeof(int) * 2);
  if (p == nullptr) {
    cerr << "malloc failed!" << endl;
    return;
  }
  free(p);
  p = nullptr;  // 避免出现野指针情况
}

int main() {
  // Test1();
  // Test2();
  Test3();
  // Test4();
  return 0;
  new
}
// new/delete 与 malloc/free区别？
// 1. 是否需要指定分配内存大小、类型检查
// 2. new/delete做两步，且灵活
// 3. 返回值
// 4. 是否需要包含头文件